/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.imenu.web.image;

import com.imenu.web.ImageConfig;
import com.imenu.web.image.ImageMode;
import com.imenu.web.image.ImageType;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

/**
 *
 * @author yunzi
 */
public final class ImageCropper implements java.io.Serializable {

    private String courseId;//menu的id
    private String menuId;//course的id
    private String type;//menu or course
    private String mode;//landscape or portrait
    private String extension;//image filename extension
    private int aimWidth;//图片的目标宽度,像素
    private int aimHeight;//图片的目标高度,像素
    private ImageSize displaySize;//显示以供裁剪的图片尺寸
    private CropRectangle crop;
    private int times;

    public ImageCropper() {
    }

    /** Creates a new instance of ImageBean */
    public ImageCropper(String menuId, String courseId, String type, String mode, String extension) {
        this();
        setMenuId(menuId);
        setCourseId(courseId);
        setType(type);
        setMode(mode);
        setExtension(extension);
    }

    public String getCourseId() {
        return courseId;
    }

    public void setCourseId(String courseId) {
        this.courseId = courseId;
    }

    public String getMenuId() {
        return menuId;
    }

    public void setMenuId(String menuId) {
        this.menuId = menuId;
    }

    public String getExtension() {
        return extension;
    }

    public void setExtension(String extension) {
        this.extension = extension;
    }

    public String getMode() {
        return mode;
    }

    public CropRectangle getCrop() throws Exception {
        if (this.crop != null) {
            return crop;
        }
        this.getSize();
        System.out.println("CropImageBean.getCrop() times = " + times);
        System.out.println("CropImageBean.getCrop() this.getAimWidth() = " + this.getAimWidth());
        System.out.println("CropImageBean.getCrop() this.getAimHeight() = " + this.getAimHeight());
        System.out.println("CropImageBean.getCrop() this.displaySize = " + this.displaySize);

        int minWidth = this.getAimWidth() / 2 / times;
        int minHeight = this.getAimHeight() / 2 / times;
        int pointX = (this.displaySize.getWidth() - minWidth) / 2;
        int pointY = (this.displaySize.getHeight() - minHeight) / 2;
        this.crop = new CropRectangle(pointX, pointY, minWidth, minHeight);
        System.out.println("CropImageBean.getCrop() this.crop = " + this.crop);
        return this.crop;
    }

    //public void setSelect(CropRectangle select) {
    //    this.select = select;
    //}
    public void setMode(String mode) {
        if ("landscape".equals(mode)) {
            this.setAimWidth(1024);
            this.setAimHeight(768);
        } else {
            this.setAimWidth(768);
            this.setAimHeight(1024);
        }
        this.mode = mode;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getImageName() {
        System.out.println("ImageCropper.getImagePath() extension = " + extension);
        if ("course".equals(type)) {
            return type + "_" + courseId + "_" + mode + extension;
        }
        return type + "_" + menuId + "_" + mode + extension;
    }

    public int getAimHeight() {
        return aimHeight;
    }

    public void setAimHeight(int aimHeight) {
        this.aimHeight = aimHeight;
    }

    public int getAimWidth() {
        return aimWidth;
    }

    public void setAimWidth(int aimWidth) {
        this.aimWidth = aimWidth;
    }

    public void setCrop(CropRectangle crop) {
        this.crop = crop;
    }

    public int getTimes() throws Exception {
        if (times == 0) {
            this.getSize();
        }
        return times;
    }

    /**上传之原始图片的大小*/
    public ImageSize getSize() throws Exception {
        Image image = ImageIO.read(new File(ImageConfig.IMAGE_TEMP_DIR+"/"+this.getImageName()));
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        if (width < aimWidth) {
            throw new Exception("图片宽度【" + width + "】太小，横图宽度宽度至少为" + aimWidth + "像素。");
        }
        if (height < aimHeight) {
            throw new Exception("图片高度【" + height + "】太小，横图宽度高度至少为" + aimHeight + "像素。");
        }
        times = Math.min(width / aimWidth, height / aimHeight);
        this.displaySize = new ImageSize((int) width / times / 2, (int) height / times / 2);
        return this.displaySize;
    }

    /*
    public Image getImage() {
        try {
            return ImageIO.read(new File(this.getImageDirRealPath()+"/"+this.getImageName()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
     */

    /** 
     * 备注：ImageIO从JDK1.4，JDK包含GIF，JPEG，PNG但是不支持GIF 
     * 创建图片的方法 
     * @param file 
     * @param outfile 
     */
    public static void createImageByImageIo(File file, File outfile, String imageFormat) {
        try {
            //源图片  
            Image src = ImageIO.read(file);
            int w = src.getWidth(null);
            int h = src.getHeight(null);
            int new_w = (int) Math.round(w * 0.2);
            int new_h = (int) Math.round(h * 0.2);
            BufferedImage tag = new BufferedImage(new_w, new_h, BufferedImage.TYPE_INT_RGB);
            tag.getGraphics().drawImage(src, 0, 0, new_w, new_h, null);        //绘制缩小后的图  
            FileOutputStream newimage = new FileOutputStream(outfile);
            //在maven中可能编译不通过，可以使用ImageIO写入文件  
            ImageIO.write(tag, imageFormat, newimage);
            newimage.close();
        } catch (Exception e) {
        }
    }

    /**一步到位，完成裁剪和缩放动作。*/
    public void cut() throws Exception {
        System.out.println("CropImageBean.cut() this.crop = " + this.crop + " this.menuId=" + this.menuId + " this.type=" + this.type + " this.mode=" + this.mode);
        System.out.println("CropImageBean.cut() this.aimWidth = " + this.aimWidth);
        System.out.println("CropImageBean.cut() this.aimHeight = " + this.aimHeight);
        System.out.println("CropImageBean.cut() this.displaySize = " + this.displaySize);
        System.out.println("CropImageBean.cut() this.crop = " + this.crop);
        FileInputStream is = null;
        ImageInputStream iis = null;

        try {
            //读取图片文件
            File file = new File(ImageConfig.IMAGE_TEMP_DIR+"/"+this.getImageName());
            System.out.println("-----------------------------CropImageBean.cut() this.getImageName() = " + this.getImageName());
            is = new FileInputStream(file);
            //获取图片流 
            iis = ImageIO.createImageInputStream(is);

            /**//*
             * 返回包含所有当前已注册 ImageReader 的 Iterator，这些 ImageReader 
             * 声称能够解码指定格式。 参数：formatName - 包含非正式格式名称 .
             *（例如 "jpeg" 或 "tiff"）等 。 
             */
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(extension.substring(1));
            ImageReader reader = it.next();
            /**//* 
             * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
             * 此设置意味着包含在输入源中的图像将只按顺序读取，可能允许 reader
             *  避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
             */
            reader.setInput(iis, true);

            /**//* 
             * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O 
             * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件
             * 将从其 ImageReader 实现的 getDefaultReadParam 方法中返回 
             * ImageReadParam 的实例。  
             */
            ImageReadParam param = reader.getDefaultReadParam();

            /**//*
             * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle 对象
             * 的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。 
             */
            //Rectangle rect = new Rectangle(x, y, width, height);
            Rectangle rect = new Rectangle(getCrop().getX() * times * 2, getCrop().getY() * times * 2, getCrop().getWidth() * times * 2, getCrop().getHeight() * times * 2);
            System.out.println("CropImageBean.cut() type = " + type);
            System.out.println("CropImageBean.cut() menuId = " + menuId);
            System.out.println("CropImageBean.cut() courseId = " + courseId);
            System.out.println("CropImageBean.cut() mode = " + mode);
            System.out.println("CropImageBean.cut() times = " + times);
            System.out.println("CropImageBean.cut() crop = " + crop);
            System.out.println("CropImageBean.cut() rect = " + rect);
            System.out.println("CropImageBean.cut() x = " + rect.getX());
            System.out.println("CropImageBean.cut() y = " + rect.getY());
            System.out.println("CropImageBean.cut() width = " + rect.getWidth());
            System.out.println("CropImageBean.cut() height = " + rect.getHeight());

            //提供一个 BufferedImage，将其用作解码像素数据的目标。 
            param.setSourceRegion(rect);

            /**//*
             * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象，并将
             * 它作为一个完整的 BufferedImage 返回。
             */
            BufferedImage bi = reader.read(0, param);

            //缩放图片
            bi.getScaledInstance(aimWidth, aimHeight, Image.SCALE_SMOOTH);
            BufferedImage scaledImage = this.resizeImage(bi, aimWidth, aimHeight, bi.getType());

            //System.out.println("CropImageBean.cut() this.filePath = " + this.imageDir);
            //this.imageName = type + "_" + id + "_" + mode + extension;

            String aimImagePath = ImageConfig.IMAGE_DIR +"/"+menuId+"/"+ this.getImageName();
            File result = new File(aimImagePath);
            if (!result.exists()) {
                result.getParentFile().mkdirs();
            } else {
                //result.delete();
            }
            System.out.println("***************CropImageBean.cut() newFilePath = " + aimImagePath);
            //保存新图片 
            ImageIO.write(scaledImage, extension.substring(1), result);
            //保存图片文件名到服务器端
            saveImageName();
            //菜品需要另存440x330和300x225两张图片，从landscape
            if (ImageMode.Landscape.getValue().equals(mode)) {
                scaledImage = scaleImage(scaledImage, 1024, 768);
                scaledImage = scaleImage(scaledImage, 440, 330);
                scaledImage = scaleImage(scaledImage, 300, 225);
                scaledImage = scaleImage(scaledImage, 100, 75);
            } else {
                scaledImage = scaleImage(scaledImage, 768, 1024);
                scaledImage = scaleImage(scaledImage, 300, 400);
                scaledImage = scaleImage(scaledImage, 75, 100);
            }

        } finally {
            if (is != null) {
                is.close();
            }
            if (iis != null) {
                iis.close();
            }
        }
    }

    private BufferedImage scaleImage(BufferedImage bi, int width, int height) throws Exception {
        String finalImagePath = ImageConfig.IMAGE_DIR+"/"+menuId+"/"+width+"x"+height+"_"+this.getImageName();
        System.out.println("ImageCropper.scaleImage() finalImagePath = "+finalImagePath);
        File smallImage = new File(finalImagePath);
        //bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage scaledImage = this.resizeImage(bi, width, height, bi.getType());
        ImageIO.write(scaledImage, extension.substring(1), smallImage);
        return scaledImage;
    }

    /**保存图片文件名到数据库*/
    private void saveImageName() {
        if (ImageType.Menu.getValue().equals(type)) {
            //saveImageNameForMenu();
        } else {
            //saveImageNameForCourse();
        }
    }

    private BufferedImage resizeImage(BufferedImage originalImage, int toWidth, int toHeight, int type) {
        BufferedImage resizedImage = new BufferedImage(toWidth, toHeight, type);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, toWidth, toHeight, null);
        g.dispose();
        return resizedImage;
    }

    private BufferedImage resizeImageWithHint(BufferedImage originalImage, int toWidth, int toHeight, int type) {
        BufferedImage resizedImage = new BufferedImage(toWidth, toHeight, type);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, toWidth, toHeight, null);
        g.dispose();
        g.setComposite(AlphaComposite.Src);

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        return resizedImage;
    }
}
